package com.zmn.plat.admin.controller.common;


import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.mcc.cas.thymeleaf.MenuPermitManager;
import com.zmn.mcc.common.constant.MenuConsts;
import com.zmn.mcc.common.dto.menu.McMenuDRO;
import com.zmn.mcc.dubbo.dto.DubboConsts;
import com.zmn.mcc.dubbo.interfaces.menu.MenuListRemoteService;
import com.zmn.plat.admin.controller.PlatBaseController;
import com.zmn.plat.common.constant.RedisKeyConstant;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


/**
 * 菜单配置表基础查询Controller
 *
 * @author guoqiao
 * @since 2021-05-28 16:23:56
 */
@Slf4j
@RestController
@RequestMapping("/menu")
public class MenuListController extends PlatBaseController {

    @Reference(version = DubboConsts.INTERFACE_VERSION, check = false)
    MenuListRemoteService menuListRemoteService;

    @Resource
    MenuPermitManager menuPermitManager;

    @Resource
    RedisTemplate redisTemplate;

    /**
     * 描述: 加载菜单
     *
     * @author guoqiao
     * @since 2021-05-28 16:23:56
     */
    @RequestMapping(value = "/loadMenu")
    public ResponseDTO<List<McMenuDRO>> loadMenu() {
        try {
            // 从redis获取
            String key = RedisKeyConstant.MENU + getMcStaffId();
            List<McMenuDRO> menuRedis = (List<McMenuDRO>) redisTemplate.opsForValue().get(key);
            if (!CollectionUtils.isEmpty(menuRedis)) {
                return ResponseDTO.success(menuRedis);
            }

            // 查询有效菜单
            ResponseDTO<List<McMenuDRO>> menuDROList = menuListRemoteService.listAllMenu();
            if (menuDROList.isSuccess()) {
                // 过滤权限
                List<McMenuDRO> menuPermitList = Optional.ofNullable(menuDROList.getData())
                        .orElse(Collections.emptyList())
                        .stream()
                        .filter(menu -> this.filterPermit(menu.getMenuPermitUrl(), menuPermitManager))
                        .collect(Collectors.toList());

                // 仅限类型为目录，按menuId分组的map集合
                Map<Integer, List<McMenuDRO>> menuIdMap = menuPermitList.stream()
                        .filter(menu -> menu.getMenuType() == MenuConsts.MENU_TYPE_WHOLE_KEY).collect(Collectors.groupingBy(McMenuDRO::getMenuId));
                // 仅限类型为菜单的集合
                List<McMenuDRO> menuList = menuPermitList.stream().filter(menu -> menu.getMenuType() == MenuConsts.MENU_TYPE_MENU_KEY).collect(Collectors.toList());

                // 遍历过滤空包
                for (McMenuDRO menu : menuList) {
                    filterEmptyPack(menuIdMap, menu.getParentId());
                }
                // 从菜单集合中移除空包
                for (Map.Entry<Integer, List<McMenuDRO>> entry : menuIdMap.entrySet()) {
                    menuPermitList.remove(entry.getValue().get(0));
                }

                // 按parentId分组的map集合
                Map<Integer, List<McMenuDRO>> parentIdMap = menuPermitList.stream().collect(Collectors.groupingBy(McMenuDRO::getParentId));
                // 构建菜单树
                List<McMenuDRO> treeMenus = this.buildTree(parentIdMap, GlobalConsts.LEVEL_1);

                // 同步redis
                if (!CollectionUtils.isEmpty(treeMenus)) {
                    redisTemplate.opsForValue().set(key, treeMenus, 5, TimeUnit.MINUTES);
                }
                return ResponseDTO.success(treeMenus);
            } else {
                log.error("dubbo调用失败");
                return ResponseDTO.fail("查询失败，程序异常");
            }
        } catch (Exception e) {
            log.error("MenuListController.loadMenu查询失败,原因:{}", e.getMessage(), e);
            return ResponseDTO.fail("查询失败，程序异常");
        }
    }

    /**
     * 描述: 判断是否有权限
     *
     * @param url 权限url
     * @return java.lang.Boolean
     * @author guoqiao
     * @since 2021/6/3 11:52
     */
    public static Boolean filterPermit(String url, MenuPermitManager menuPermitManager) {

        if (StringUtil.isBlank(url)) {
            return true;
        }
        return menuPermitManager.checkMenuPermit(url);
    }

    /**
     * 描述: 过滤空包
     * <p>从菜单向上递归查询所有的父级，找到的从map中移除，递归完后剩余的就是空包</p>
     *
     * @param menuIddMap 按menuId分组的map集合
     * @param menuId     菜单id
     * @author guoqiao
     * @since 2021/6/3 11:52
     */
    public static void filterEmptyPack(Map<Integer, List<McMenuDRO>> menuIddMap, Integer menuId) {

        List<McMenuDRO> menuList = menuIddMap.get(menuId);
        if (!CollectionUtils.isEmpty(menuList)) {
            // 从map移除
            menuIddMap.remove(menuId);
            if (menuList.get(0).getParentId() != GlobalConsts.LEVEL_1) {
                filterEmptyPack(menuIddMap, menuList.get(0).getParentId());
            }
        }
    }

    /**
     * 描述: 构建菜单树形结构
     *
     * @param parentIdMap 菜单集合
     * @param parentId    需要递归遍历的父级id
     * @return java.util.List<com.zmn.mcc.common.dto.menu.McMenuDRO>
     * @author guoqiao
     * @since 2021/6/02 10:32
     */
    public static List<McMenuDRO> buildTree(Map<Integer, List<McMenuDRO>> parentIdMap, int parentId) {
        List<McMenuDRO> treeList = new ArrayList<>();
        List<McMenuDRO> list = parentIdMap.get(parentId);
        if (!CollectionUtils.isEmpty(list)) {
            for (McMenuDRO menu : list) {
                // 只有目录才设置子类
                if (menu.getMenuType() == MenuConsts.MENU_TYPE_WHOLE_KEY) {
                    menu.setSubMenuList(buildTree(parentIdMap, menu.getMenuId()));
                }
                treeList.add(menu);
            }
        }
        return treeList;
    }
}
